﻿
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Reflection;
using System.Threading.Tasks;
using DotNetCore.CAP;
using Microsoft.Extensions.Configuration;

namespace Hx.EventBus
{
    /// <summary>
    /// 事件总线配置选项构建器
    /// </summary>
    public sealed class EventBusOptionsBuilder
    {
        /// <summary>
        /// 事件订阅者类型集合
        /// </summary>
        private readonly List<Type> _eventSubscribers = new List<Type>();

        /// <summary>
        /// 事件发布者类型
        /// </summary>
        private Type _eventPublisher;

        /// <summary>
        /// 事件存储器实现工厂
        /// </summary>
        private Func<IServiceProvider, IEventSourceStorer> _eventSourceStorerImplementationFactory;

        /// <summary>
        /// 事件处理程序监视器
        /// </summary>
        private Type _eventHandlerMonitor;

        /// <summary>
        /// 事件处理程序执行器
        /// </summary>
        private Type _eventHandlerExecutor;

        /// <summary>
        /// 事件重试策略类型集合
        /// </summary>
        private readonly List<Type> _fallbackPolicyTypes = new List<Type>();

        /// <summary>
        /// 默认内置事件源存储器内存通道容量
        /// </summary>
        /// <remarks>超过 n 条待处理消息，第 n+1 条将进入等待，默认为 3000</remarks>
        public int ChannelCapacity { get; set; } = 3000;

        /// <summary>
        /// 是否使用 UTC 时间戳，默认 false
        /// </summary>
        public bool UseUtcTimestamp { get; set; } = false;

        /// <summary>
        /// 是否启用模糊匹配消息
        /// </summary>
        /// <remarks>支持正则表达式</remarks>
        public bool FuzzyMatch { get; set; } = false;

        /// <summary>
        /// 是否启用执行完成触发 GC 回收
        /// </summary>
        public bool GCCollect { get; set; } = true;

        /// <summary>
        /// 是否启用日志记录
        /// </summary>
        public bool EnabledLog { get; set; } = true;

        /// <summary>
        /// 重试失败策略配置
        /// </summary>
        public Type FallbackPolicy { get; set; }

        /// <summary>
        /// 是否启用EventBus
        /// </summary>
        public bool? IsEnabled { get; set; }

        /// <summary>
        /// 是否使用Cap
        /// </summary>
        public bool? UseCap { get; set; } = false;

        /// <summary>
        /// cap相关配置
        /// </summary>
        public Action<CapOptions> CapOptions { get; set; }

        /// <summary>
        /// 未察觉任务异常事件处理程序
        /// </summary>
        public EventHandler<UnobservedTaskExceptionEventArgs> UnobservedTaskExceptionHandler { get; set; }

        /// <summary>
        /// 注册事件订阅者
        /// </summary>
        /// <typeparam name="TEventSubscriber">实现自 <see cref="IEventSubscriber"/></typeparam>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder AddSubscriber<TEventSubscriber>()
            where TEventSubscriber : class, IEventSubscriber
        {
            _eventSubscribers.Add(typeof(TEventSubscriber));
            return this;
        }

        /// <summary>
        /// 注册事件订阅者
        /// </summary>
        /// <param name="eventSubscriberType"><see cref="IEventSubscriber"/> 派生类型</param>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder AddSubscriber(Type eventSubscriberType)
        {
            // 类型检查
            if (!typeof(IEventSubscriber).IsAssignableFrom(eventSubscriberType) || eventSubscriberType.IsInterface) throw new InvalidOperationException("The <eventSubscriberType> is not implement the IEventSubscriber interface.");

            _eventSubscribers.Add(eventSubscriberType);
            return this;
        }

        /// <summary>
        /// 批量注册事件订阅者
        /// </summary>
        /// <param name="assemblies">程序集</param>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder AddSubscribers(params Assembly[] assemblies)
        {
            if (assemblies == null || assemblies.Length == 0)
            {
                throw new InvalidOperationException("The assemblies can be not null or empty.");
            }

            // 获取所有导出类型（非接口，非抽象类且实现 IEventSubscriber）接口
            var subscribers = assemblies.SelectMany(ass =>
                  ass.GetExportedTypes()
                     .Where(t => t.IsPublic && t.IsClass && !t.IsInterface && !t.IsAbstract && typeof(IEventSubscriber).IsAssignableFrom(t)));

            foreach (var subscriber in subscribers)
            {
                _eventSubscribers.Add(subscriber);
            }

            return this;
        }

        /// <summary>
        /// 替换事件发布者
        /// </summary>
        /// <typeparam name="TEventPublisher">实现自 <see cref="IEventPublisher"/></typeparam>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder ReplacePublisher<TEventPublisher>()
            where TEventPublisher : class, IEventPublisher
        {
            _eventPublisher = typeof(TEventPublisher);
            return this;
        }

        /// <summary>
        /// 替换事件源存储器
        /// </summary>
        /// <param name="implementationFactory">自定义事件源存储器工厂</param>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder ReplaceStorer(Func<IServiceProvider, IEventSourceStorer> implementationFactory)
        {
            _eventSourceStorerImplementationFactory = implementationFactory;
            return this;
        }

        /// <summary>
        /// 替换事件源存储器（如果初始化失败则回退为默认的）
        /// </summary>
        /// <param name="createStorer"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public EventBusOptionsBuilder ReplaceStorerOrFallback(Func<IEventSourceStorer> createStorer)
        {
            // 空检查
            if (createStorer == null) throw new ArgumentNullException(nameof(createStorer));

            try
            {
                // 创建事件源存储器
                var storer = createStorer.Invoke();

                // 替换事件源存储器
                ReplaceStorer(_ => storer);
            }
            catch { }

            return this;
        }

        /// <summary>
        /// 替换事件源存储器（如果初始化失败则回退为默认的）
        /// </summary>
        /// <param name="createStorer"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public EventBusOptionsBuilder ReplaceStorerOrFallback(Func<IServiceProvider, IEventSourceStorer> createStorer)
        {
            // 空检查
            if (createStorer == null) throw new ArgumentNullException(nameof(createStorer));

            // 替换事件源存储器
            ReplaceStorer(serviceProvider =>
            {
                try
                {
                    return createStorer.Invoke(serviceProvider);
                }
                catch
                {
                    return new ChannelEventSourceStorer(ChannelCapacity);
                }
            });

            return this;
        }

        /// <summary>
        /// 注册事件处理程序监视器
        /// </summary>
        /// <typeparam name="TEventHandlerMonitor">实现自 <see cref="IEventHandlerMonitor"/></typeparam>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder AddMonitor<TEventHandlerMonitor>()
            where TEventHandlerMonitor : class, IEventHandlerMonitor
        {
            _eventHandlerMonitor = typeof(TEventHandlerMonitor);
            return this;
        }

        /// <summary>
        /// 注册事件处理程序执行器
        /// </summary>
        /// <typeparam name="TEventHandlerExecutor">实现自 <see cref="IEventHandlerExecutor"/></typeparam>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder AddExecutor<TEventHandlerExecutor>()
            where TEventHandlerExecutor : class, IEventHandlerExecutor
        {
            _eventHandlerExecutor = typeof(TEventHandlerExecutor);
            return this;
        }

        /// <summary>
        /// 注册事件重试策略
        /// </summary>
        /// <typeparam name="TEventFallbackPolicy">实现自 <see cref="IEventFallbackPolicy"/></typeparam>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder AddFallbackPolicy<TEventFallbackPolicy>()
            where TEventFallbackPolicy : class, IEventFallbackPolicy
        {
            _fallbackPolicyTypes.Add(typeof(TEventFallbackPolicy));
            return this;
        }

        /// <summary>
        /// 注册事件重试策略
        /// </summary>
        /// <param name="fallbackPolicyType"><see cref="IEventFallbackPolicy"/> 派生类型</param>
        /// <returns><see cref="EventBusOptionsBuilder"/> 实例</returns>
        public EventBusOptionsBuilder AddFallbackPolicy(Type fallbackPolicyType)
        {
            // 类型检查
            if (!typeof(IEventFallbackPolicy).IsAssignableFrom(fallbackPolicyType) || fallbackPolicyType.IsInterface) throw new InvalidOperationException("The <fallbackPolicyType> is not implement the IEventFallbackPolicy interface.");

            _fallbackPolicyTypes.Add(fallbackPolicyType);
            return this;
        }

        /// <summary>
        /// 构建事件总线配置选项
        /// </summary>
        /// <param name="services">服务集合对象</param>
        internal void Build(IServiceCollection services)
        {
            // 注册事件订阅者
            foreach (var eventSubscriber in _eventSubscribers)
            {
                services.AddSingleton(typeof(IEventSubscriber), eventSubscriber);
            }

            // 替换事件发布者
            if (_eventPublisher != default)
            {
                services.Replace(ServiceDescriptor.Singleton(typeof(IEventPublisher), _eventPublisher));
            }

            // 替换事件存储器
            if (_eventSourceStorerImplementationFactory != default)
            {
                services.Replace(ServiceDescriptor.Singleton(_eventSourceStorerImplementationFactory));
            }

            // 注册事件监视器
            if (_eventHandlerMonitor != default)
            {
                services.AddSingleton(typeof(IEventHandlerMonitor), _eventHandlerMonitor);
            }

            // 注册事件执行器
            if (_eventHandlerExecutor != default)
            {
                services.AddSingleton(typeof(IEventHandlerExecutor), _eventHandlerExecutor);
            }

            // 注册事件重试策略
            foreach (var fallbackPolicyType in _fallbackPolicyTypes)
            {
                services.AddSingleton(fallbackPolicyType);
            }
        }

        /// <summary>
        /// 初始化EventBusOptionsBuilder
        /// </summary>
        /// <returns></returns>
        internal static EventBusOptionsBuilder Init(IConfiguration configuration)
        {
            var builder = new EventBusOptionsBuilder();
            _ = bool.TryParse(configuration["EventBus:IsEnabled"], out bool isEnabled);
            builder.IsEnabled = isEnabled;
            _ = bool.TryParse(configuration["EventBus:UseCap"], out bool useCap);
            builder.UseCap= useCap;
            int.TryParse(configuration["EventBus:ChannelCapacity"], out int channelCapacity);
            if (channelCapacity > 0) builder.ChannelCapacity = channelCapacity;
            _ = bool.TryParse(configuration["EventBus:EnabledLog"], out bool enabledLog);
            builder.EnabledLog= enabledLog;
            _ = bool.TryParse(configuration["EventBus:FuzzyMatch"], out bool fuzzyMatch);
            builder.FuzzyMatch = fuzzyMatch;
            _ = bool.TryParse(configuration["EventBus:GCCollect"], out bool gCCollect);
            builder.GCCollect = gCCollect;
            _ = bool.TryParse(configuration["EventBus:UseUtcTimestamp"], out bool useUtcTimestamp);
            builder.UseUtcTimestamp = useUtcTimestamp;
            return builder;
        }

        /// <summary>
        /// 初始化CapOptions
        /// </summary>
        /// <param name="configuration"></param>
        /// <returns></returns>
        internal static Action<CapOptions> InitCapOptions(IConfiguration configuration)
        {
            return (CapOptions options) => 
            {
                options.DefaultGroupName = configuration["EventBus:Cap:DefaultGroupName"];
                int failedRetryCount = 5;
                var failedRetryCountStr = configuration["EventBus:Cap:FailedRetryCount"];
                if (!string.IsNullOrEmpty(failedRetryCountStr))
                    _ = int.TryParse(failedRetryCountStr, out failedRetryCount);
                options.FailedRetryCount = failedRetryCount;
                var failedRetryIntervalStr = configuration["EventBus:Cap:FailedRetryCount"];
                if (!string.IsNullOrEmpty(failedRetryIntervalStr))
                {
                    int failedRetryInterval = 60;
                    _ = int.TryParse(failedRetryIntervalStr, out failedRetryInterval);
                    options.FailedRetryInterval = failedRetryInterval;
                }
                options.UseRabbitMQ(options =>
                {
                    var portStr = configuration["EventBus:RabbitMQ:Port"];
                    int port = 5672;
                    if (!string.IsNullOrEmpty(portStr)) _ = int.TryParse(portStr, out port);
                    options.HostName = configuration["EventBus:RabbitMQ:HostName"];
                    options.VirtualHost = configuration["EventBus:RabbitMQ:VirtualHost"];
                    options.UserName = configuration["EventBus:RabbitMQ:UserName"];
                    options.Password = configuration["EventBus:RabbitMQ:Password"];
                    options.Port = port;
                });
            };
        }
    }
}

